//
//  CompressHelper.m
//  CompressHelper
//
//  Created by cr on 2021/5/31.
//

#import <Foundation/Foundation.h>
#import <React/RCTEventEmitter.h>
#define ERROR_CLEANUP_ERROR_KEY @"E_ERROR_WHILE_CLEANING_FILES"
#define ERROR_CLEANUP_ERROR_MSG @"Error while cleaning up tmp files"
@interface CompressHelper : RCTEventEmitter<RCTBridgeModule>

@end

@implementation CompressHelper

RCT_EXPORT_MODULE()

RCT_REMAP_METHOD(compress, params
                 : (NSDictionary *)dict
                 : (RCTPromiseResolveBlock)resolve
                 : (RCTPromiseRejectBlock)reject) {
    NSString* path =  [dict valueForKey:@"path"];
    UIImage *image = [UIImage imageWithContentsOfFile:path];
    int maxSize = [[dict valueForKey:@"limitSize"] intValue]*1024;

      CGFloat compression = 1 ;
      NSData *data = UIImageJPEGRepresentation(image, 1);
      int maxLength = maxSize;
      if(data.length < maxLength){

          NSString * path = [self persistFile:data];
          resolve(@{@"path":path,@"width":@(image.size.width),@"height":@(image.size.height),@"mime":@"image/jpeg",@"size":@(data.length)});
          return;
      }

      CGFloat max = 1;
      CGFloat min = 0;
      for(int i=0;i<10;++i)
      {
          compression = (max+min)/2;
          data = UIImageJPEGRepresentation(image,compression);
          if(data.length < maxLength*0.9)
          {
              min = compression;
          }
          else if(data.length > maxLength)
          {
              max = compression;
          }
          else{
              break;
          }
      }

      UIImage* img = [UIImage imageWithData:data];
      if(data.length < maxLength){
          NSString * path = [self persistFile:data];
          resolve(@{@"path":path,@"width":@(img.size.width),@"height":@(img.size.height),@"mime":@"image/jpeg",@"size":@(data.length)});
          return;
      }

      NSUInteger lastDataLength = 0;

      while(data.length > maxLength && data.length != lastDataLength)
      {
          lastDataLength = data.length;
          CGFloat ratio = (CGFloat)maxLength/data.length;
          CGSize size = CGSizeMake((NSUInteger)(img.size.width*sqrtf(ratio)),(NSUInteger)(img.size.height*sqrtf(ratio)));
          UIGraphicsBeginImageContext(size);
          [img drawInRect:CGRectMake(0, 0, size.width, size.height)];
          img = UIGraphicsGetImageFromCurrentImageContext();
                 UIGraphicsEndImageContext();
          data = UIImageJPEGRepresentation(img, compression);
      }

    NSString * newPath = [self persistFile:data];
    resolve(@{@"path":newPath,@"width":@(img.size.width),@"height":@(img.size.height),@"mime":@"image/jpeg",@"size":@(data.length)});
}
+(BOOL)requiresMainQueueSetup
{
    return YES;
}

- (NSArray<NSString *> *)supportedEvents {
    return @[@"CompressHelper"];
}

- (NSString*) getTmpDirectory {
    NSString *TMP_DIRECTORY = @"react-native-cr-compress/";
    NSString *tmpFullPath = [NSTemporaryDirectory() stringByAppendingString:TMP_DIRECTORY];
    
    BOOL isDir;
    BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:tmpFullPath isDirectory:&isDir];
    if (!exists) {
        [[NSFileManager defaultManager] createDirectoryAtPath: tmpFullPath
                                  withIntermediateDirectories:YES attributes:nil error:nil];
    }
    
    return tmpFullPath;
}

- (NSString*) persistFile:(NSData*)data {
    // create temp file
    NSString *tmpDirFullPath = [self getTmpDirectory];
    NSString *filePath = [tmpDirFullPath stringByAppendingString:[[NSUUID UUID] UUIDString]];
    filePath = [filePath stringByAppendingString:@".jpg"];
    
    // save cropped file
    BOOL status = [data writeToFile:filePath atomically:YES];
    if (!status) {
        return nil;
    }
    
    return filePath;
}
- (BOOL)cleanTmpDirectory {
    NSString* tmpDirectoryPath = [self getTmpDirectory];
    NSArray* tmpDirectory = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:tmpDirectoryPath error:NULL];
    
    for (NSString *file in tmpDirectory) {
        BOOL deleted = [[NSFileManager defaultManager] removeItemAtPath:[NSString stringWithFormat:@"%@%@", tmpDirectoryPath, file] error:NULL];
        
        if (!deleted) {
            return NO;
        }
    }    
    return YES;
}
RCT_REMAP_METHOD(clean, resolver:(RCTPromiseResolveBlock)resolve
                 rejecter:(RCTPromiseRejectBlock)reject) {
    if (![self cleanTmpDirectory]) {
        reject(ERROR_CLEANUP_ERROR_KEY, ERROR_CLEANUP_ERROR_MSG, nil);
    } else {
        resolve(nil);
    }
}
@end
